package net
{
	import flash.events.ProgressEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;

	public class SocketEx extends Socket
	{
		
		private var callBackList:Dictionary;//回调函数列表
		private var baSendByteArray:ByteArray = new ByteArray();//负责发送的ByteArray
		
		//包头协议大小定义
		private var headeSize:int = 2;
		private var cmdSize:int =1;
		private var headAndCmdLen:int = 3;
		
		//读取状态
		private var receState:int = RECE_HEAD;
		private const RECE_HEAD:int = 0;
		private const RECE_CMD:int = 1;
		private const RECE_BODY:int =2;

		public function SocketEx()
		{
			callBackList = new Dictionary(true);
			
			addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
		}
		
		protected function onSocketData(event:ProgressEvent):void
		{
			
			recvData();

		}
		
		
		private function recvData():void
		{
			
			var nSize:int = 0;
			var nCmd:int = 0;
			
			if(receState == RECE_HEAD && bytesAvailable >= headeSize)
			{
				nSize = readShort() - headAndCmdLen;
				receState = RECE_CMD;
			}
			
			if(receState == RECE_CMD &&  bytesAvailable >= cmdSize)
			{
				nCmd = readByte();
				receState = RECE_BODY;
			}
			
			if(receState == RECE_BODY && bytesAvailable >= nSize)
			{
				receState = RECE_HEAD;
				
				var baArray:ByteArray = new ByteArray();
				readBytes(baArray, 0, nSize);
				
				var str:String = "【接收数据】包长:{" + nSize + "}" + "cmd:{" + nCmd + "}  = ";
				
				while(baArray.bytesAvailable)
				{
					str += baArray.readUnsignedByte() + ",";
				}
				trace(str);
				
				baArray.position = 0;
				var fun:Function = callBackList[nCmd] as Function;
				if(fun)
					fun(baArray);
	
				baArray.clear();
				baArray = null;
				
				if(bytesAvailable > 0)
					recvData();
				
			}
			
		}

		
		/**
		 * 发送数据 
		 * 
		 */		
		public function send():void
		{
			var nMaxSize:int = baSendByteArray.length  + 2;
			
			writeShort(nMaxSize);
			writeBytes(baSendByteArray);
			flushClear(baSendByteArray, nMaxSize);
		}
		
		private function flushClear(byteArray:ByteArray, bodyLen:int):void
		{
			flush();
			byteArray.position = 0;
			var cmd:int = byteArray.readShort();
			
			var str:String = "【发送数据】包长:{" + bodyLen + "}" + "cmd:{" + cmd + "} = ";
			
			while(byteArray.bytesAvailable)
			{
				str += byteArray.readUnsignedByte() + ",";
			}
			
			trace(str);
			
			byteArray.clear();
		}		
		
		/**
		 *　获取发送的 ByteArray
		 * @return 
		 * 
		 */		
		public function get sendByteArray():ByteArray
		{
			return baSendByteArray;
		}
		
		/**
		 *　注册网络回调 
		 * @param cmdId　协议ＩＤ
		 * @param callback　回调函数
		 * 
		 */		
		public function resCallBack(cmdId:uint, callback:Function):void
		{
			callBackList[cmdId] = callback;
		}
		
		
		/**
		 *　向字节流写入字符 
		 * @param str　要写入的字符
		 * @param ba　　被写入的字节流
		 * 
		 */		
		public static function writeString(str:String, ba:ByteArray):void
		{
			var len:int = 0;
			var babuff:ByteArray = new ByteArray();
			babuff.writeUTFBytes(str);
			len = babuff.length;
			babuff = null;
			
			ba.writeByte(len);
			ba.writeUTFBytes(str);
		}
		
		/**
		 *　从字体流读取字符 
		 * @param ba　需要读取字符的字节流
		 * @return 
		 * 
		 */		
		public static function readString(ba:ByteArray):String
		{
			var str:String = ba.readUTFBytes(ba.readUnsignedByte());
			return str;
		}
		
		
		/**
		 *　 Gb2312字符写入，(与Ｃ++连接的时候用)
		 * @param baMsg　	被写入的节字流
		 * @param str　　　	写入的字符
		 * @param nSize　　	字符个数
		 * 
		 */		
		public static function writeStringGb2312(baMsg:ByteArray, str:String, nSize:int):void
		{
			var ba:ByteArray = new ByteArray();
			ba.writeMultiByte(str, "gb2312");
			
			//大于或是等于都提示错误，要预留一字节结尾\0
			if(ba.length >= nSize)
				throw new Error("字节串过长,"+str);
			
			var num:int = nSize - ba.length;
			
			for(var i:int=0; i<num; i++)
			{
				ba.writeByte(0);
			}
			baMsg.writeBytes(ba);
		}
	
		/**
		 * Gb2312字符读取(与Ｃ++连接的时候用)
		 * @param baMsg
		 * @param nSize
		 * @return 
		 * 
		 */		
		public static function readStringGb2312(baMsg:ByteArray, nSize:int):String
		{
			var str:String = baMsg.readMultiByte(nSize, "gb2312");
			return str;
		}
		
		
		
		public static function writeLong(n:Number, ba:ByteArray):void
		{
			ba.writeUnsignedInt(int(Number(n)/(uint.MAX_VALUE+1)));
			ba.writeUnsignedInt(int(n));
		}
		
		public static function readLong(ba:ByteArray):Number
		{
			return ba.readUnsignedInt() * (uint.MAX_VALUE + 1) + ba.readUnsignedInt();
		}
		
	}
}